#include <iostream>
extern "C"
{
    #include <libavcodec/avcodec.h>
}
#include "MYDecode.h"

using namespace std;

// 释放pkt   AVPacket（存储一帧压缩编码数据）
void MYFreePacket(AVPacket **pkt)
{
    if(!pkt || !(*pkt)) return;
    av_packet_free(pkt);
}

// 释放frame  AVFrame（存储一帧解码后像素（采样）数据）
void MYFreeFrame(AVFrame **frame)
{
    if(!frame || !(*frame)) return;
    av_frame_free(frame);
}

// AVCodecParameters 音视频参数 (音频和视频分开的)
bool MYDecode::Open(AVCodecParameters *para)
{
    if(!para) return false;
    // 清理一下数据
    Close();
    // 寻找解码器 AVCodec（每种视频（音频）编解码器（例如H.264解码器）对应一个结构体）
    AVCodec *avCodec = avcodec_find_decoder(para->codec_id);
    if(!avCodec) {
        avcodec_parameters_free(&para);
        // 留着写日志
        cout << "can't find the codec id " << para->codec_id << endl;
        return false;
    }
    cout << "find the AVCodec " << para->codec_id << endl;

    mux.lock();

    // 创建解码器上下文
    codec = avcodec_alloc_context3(avCodec);

    // 配置解码器上下文参数
    int ret = avcodec_parameters_to_context(codec, para);

    if(ret < 0) {
        cout << "avcodec_parameters_to_context failed" << endl;
    }
    avcodec_parameters_free(&para);

    // 8线程解码
    codec->thread_count = 8;

    // 打开解码器上下文
    ret = avcodec_open2(codec, NULL, NULL);
    // 打开失败
    if(ret != 0) {
        // 释放上下文
        avcodec_free_context(&codec);
        mux.unlock();
        char buf[1024] = {'0'};
        av_strerror(ret, buf, sizeof(buf) - 1);
        cout << "avcodec_open2  failed! :" << buf << endl;
        return false;
    }
    mux.unlock();
    cout << " avcodec_open2 success!" << endl;
    return true;
}

// 发送到解码线程，不管成功与否都释放pkt空间（对象和媒体内容）
bool MYDecode::Send(AVPacket *pkt)
{
    if(!pkt || pkt->size <= 0 || !pkt->data) return false;
    mux.lock();
    if(!codec) {
        mux.unlock();
        return false;
    }

    int ret = avcodec_send_packet(codec, pkt);
    mux.unlock();
    av_packet_free(&pkt);

    if(ret != 0) return false;
    return true;
}

//获取解码数据，一次send可能需要多次Recv，获取缓冲中的数据Send NULL在Recv多次
//每次复制一份，由调用者释放 av_frame_free
AVFrame* MYDecode::Recv()
{
    mux.lock();
    if(!codec) {
        mux.unlock();
        return NULL;
    }
    AVFrame *frame = av_frame_alloc();

    int ret = avcodec_receive_frame(codec, frame);
    mux.unlock();

    if(ret != 0) {
        av_frame_free(&frame);
        return NULL;
    }

    pts = frame->pts;
    return frame;
}

void MYDecode::Close()
{
    mux.lock();
    if(codec) {
        avcodec_close(codec);
        avcodec_free_context(&codec);
    }
    pts = 0;
    mux.unlock();
}

void MYDecode::Clear()
{
    mux.lock();
    // 清理解码缓冲
    if(codec) avcodec_flush_buffers(codec);
    mux.unlock();
}

MYDecode::MYDecode()
{
}


MYDecode::~MYDecode()
{
}
